//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#include "cword.h"
#include "../cinterpreter.h"

#include <buola/os/cuser.h>

namespace buola { namespace bush {

void CWord::AppendTokens(const TTokenRange &pR)
{
    std::wstring lResult;
    for(auto i=pR.first;i!=pR.second;++i)
    {
        switch(i->mToken)
        {
        case TOKEN_STRING_S:
        case TOKEN_STRING_D:
        case TOKEN_STRING_I:
            mFormat|=FORMAT_ESCAPED;
            lResult+=QuotedToEscaped(i->mB+1,i->mE-1);
            break;
        case TOKEN_STRING_TS:
        case TOKEN_STRING_TD:
        case TOKEN_STRING_TI:
            mFormat|=FORMAT_ESCAPED;
            lResult+=QuotedToEscaped(i->mB+3,i->mE-3);
            break;
        case TOKEN_INCOMPLETESTRING_S:
        case TOKEN_INCOMPLETESTRING_D:
        case TOKEN_INCOMPLETESTRING_I:
            mFormat|=FORMAT_ESCAPED;
            lResult+=QuotedToEscaped(i->mB+1,i->mE);
            break;
        case TOKEN_INCOMPLETESTRING_TS:
        case TOKEN_INCOMPLETESTRING_TD:
        case TOKEN_INCOMPLETESTRING_TI:
            mFormat|=FORMAT_ESCAPED;
            lResult+=QuotedToEscaped(i->mB+3,i->mE);
            break;
        case TOKEN_ESCAPEDCHAR:
            mFormat|=FORMAT_ESCAPED;
            lResult.append(i->mB,i->mE);
            break;
        case TOKEN_LEFT_BRACE:
            mFormat|=FORMAT_BRACES;
            lResult.append(i->mB,i->mE);
            break;
        case TOKEN_LEFT_SQUARE:
        case TOKEN_OP_STAR:
        case TOKEN_OP_STAREQUAL:
        case TOKEN_OP_POWER:
        case TOKEN_OP_POWEREQUAL:
        case TOKEN_OP_QUESTION:
            mFormat|=FORMAT_GLOB;
            lResult.append(i->mB,i->mE);
            break;
        case TOKEN_OP_TILDE:
            mFormat|=FORMAT_TILDE;
            lResult.append(i->mB,i->mE);
            break;
        default:
            lResult.append(i->mB,i->mE);
            break;
        }
    }
    mChars+=utf8(lResult);
}

void CWord::AppendRawText(const std::string &pString)
{
    mFormat|=FORMAT_ESCAPED;
    mChars+=RawToEscaped(pString.begin(),pString.end());
}

void CWord::AppendQuotedText(const std::string &pString)
{
    mFormat|=FORMAT_ESCAPED;
    mChars+=QuotedToEscaped(pString.begin(),pString.end());
}

std::wstring CWord::RawToEscaped(const std::wstring::const_iterator &pB,
                                const std::wstring::const_iterator &pE)
{
    std::wstring lResult;
    
    for(auto lI=pB;lI!=pE;++lI)
    {
        switch(*lI)
        {
        case '\\':
        case '*':
        case '?':
        case '[':
        case ']':
        case '{':
        case ',':
        case '}':
        case '~':
            lResult+='\\';
        default:
            lResult+=*lI;
            break;
        }
    }

    return lResult;
}

std::wstring CWord::QuotedToEscaped(const std::wstring::const_iterator &pB,
                                const std::wstring::const_iterator &pE)
{
    std::wstring lResult;
    
    for(auto lI=pB;lI!=pE;++lI)
    {
        if(*lI=='\\')
        {
            ++lI;
            assert(lI!=pE);
        }
        
        switch(*lI)
        {
        case '\\':
        case '*':
        case '?':
        case '[':
        case ']':
        case '{':
        case ',':
        case '}':
        case '~':
            lResult+='\\';
        default:
            lResult+=*lI;
            break;
        }
    }

    return lResult;
}

std::string CWord::RawToEscaped(const std::string::const_iterator &pB,
                               const std::string::const_iterator &pE)
{
    std::string lResult;
    
    for(auto lI=pB;lI!=pE;++lI)
    {
        switch(*lI)
        {
        case '\\':
        case '*':
        case '?':
        case '[':
        case ']':
        case '{':
        case ',':
        case '}':
        case '~':
            lResult+='\\';
        default:
            lResult+=*lI;
            break;
        }
    }

    return lResult;
}

std::string CWord::QuotedToEscaped(const std::string::const_iterator &pB,
                               const std::string::const_iterator &pE)
{
    std::string lResult;
    
    for(auto lI=pB;lI!=pE;++lI)
    {
        if(*lI=='\\')
        {
            ++lI;
            assert(lI!=pE);
        }
        
        switch(*lI)
        {
        case '\\':
        case '*':
        case '?':
        case '[':
        case ']':
        case '{':
        case ',':
        case '}':
        case '~':
            lResult+='\\';
        default:
            lResult+=*lI;
            break;
        }
    }

    return lResult;
}

std::wstring CWord::EscapeBack(const std::wstring::const_iterator &pB,
                           const std::wstring::const_iterator &pE)
{
    std::wstring lResult;
    
    for(auto lI=pB;lI!=pE;++lI)
    {
        if(*lI=='\\')
        {
            ++lI;
            assert(lI!=pE);
        }
        
        switch(*lI)
        {
        case '\\':
        case '*':
        case '#':
        case '?':
        case '[':
        case ']':
        case '{':
        case ',':
        case '}':
        case '(':
        case ')':
        case '\'':
        case '\"':
        case '`':
        case '<':
        case '>':
        case '|':
        case '&':
        case '!':
        case ' ':
            lResult+='\\';
        default:
            lResult+=*lI;
            break;
        }
    }

    return lResult;
}

std::wstring CWord::Quote(const std::wstring::const_iterator &pB,
                           const std::wstring::const_iterator &pE)
{
    std::wstring lResult=L"'";
    
    for(auto lI=pB;lI!=pE;++lI)
    {
        switch(*lI)
        {
        case '\\':
        case '\'':
            lResult+='\\';
        default:
            lResult+=*lI;
            break;
        }
    }
    lResult+='\'';

    return lResult;
}

void CWord::ExpandTilde()
{
    if(!mFormat&FORMAT_TILDE) return;

    if(mChars[0]=='~')
    {
        int c;
        for(c=1;c<mChars.size();c++)
        {
            if(mChars[c]=='\\')
            {
                c=-1;
                break;
            }
            else if(mChars[c]=='/')
                break;
        }
        
        if(c<0) return; //something was escaped... ignore it

        if(c==1)
        {
            mChars=io::get_home().Path()+mChars.substr(c);
        }
        else
        {
            os::CUser lUser(mChars.substr(1,c-1));
            if(!lUser) return;
            mChars=lUser.Home()+mChars.substr(c);
        }
    }
}

void CWord::GetUnescaped(std::string& pDst)
{
    pDst.resize(mChars.length());
    
    int j=0;
    for(int i=0;i<mChars.length();i++)
    {
        if(mChars[i]=='\\') i++;
        pDst[j++]=mChars[i];
    }

    pDst.resize(j);
}

/*namespace bush*/ } /*namespace buola*/ }
